#include "PSSwitch.h"

//************************************
// Method:    	tPSSwitch				判断站状态为主站或从站
// Programmer:  lww
// Time:		2018/12/22
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void *tPSSwitch(void* arg)
{
#define MAX_JUDGE_NUM	5				//< 最大失误判断次数
#define DELAY_MS	50					//< 每轮串口工作延时时间（ms）
#define PORT_SENDandRECV_WAIT_MS	100	//< 最大等待串口收发时间（ms）即串口接收和发送的超时

	int i;
	int fd = -1;  //串口设备描述符
	char tmp_char;	//接收到的数据
	int count = 0;

	printf("the Kernel_%s is %d\r\n", "tPSSwitch_ID", syscall(SYS_gettid));				//< duan20200610
	//< 初始化串口
	//< 参数一：打开串口的设备描述符
	//< 参数二：属性设置，依次为：
	//< 		O_RDWR——读写打开
	//<			O_NOCTTY——如果设备描述符指的是终端设备，则不将此设备分配作为此进程的控制终端(可以告诉Linux这个程序不会成为这个端口上的“控制终端”.如果不这样做的话,所有的输入,比如键盘上过来的Ctrl+C中止信号等等,会影响到你的进程。)
	//<			O_NDELAY——告诉Linux,这个程序并不关心DCD信号线的状态——也就是不关心端口另一端是否已经连接(非阻塞)
	//< 返回值：fd 配置好的串口
	if ((fd = Port_Open(PORT_PSSWITCH, true, O_RDWR | O_NOCTTY | O_NDELAY, B9600, CS8, 0, 1)) < 0)
	{
		perror(PORT_PSSWITCH);
		printf("Open failed\r\n");
		return NULL;
	}

	/*
		初次上电判断主从站身份:
		如接收到消息，则主站已存在，判定当前身份为从站;
		如果连续多次未收到消息，则判定没有站存在，当前站为主站;
	*/	
	for (i = 0; i < MAX_JUDGE_NUM; i++)
	{
		ExactDelay(DELAY_MS);
		int PortRecvLength = Port_Recv(fd, &tmp_char, 1, PORT_SENDandRECV_WAIT_MS, true);
		Clear_Port_Register(fd, CLEAR_IN);/*清空串口接收缓存区*/
		if (PortRecvLength < 1)
		{
			printf("PSSwitch: Recv wrong in first time\r\n");
			continue;
		}
		else
		{
			SYS_Role_Turn(Slave_Role);
			break;
		}
	}
	if (SYS_Role != Slave_Role)
		SYS_Role_Turn(Master_Alone_Role);

	//< 实时主从切换判断
	while (1)
	{
		ExactDelay(DELAY_MS);
		/*
			从站一直接收主站消息:
			如果接收失败并累计够一定次数，则连续发送几次“从站切换为主站”信号，并进行身份切换;
			如果接收成功，则向主站发送从站在运行的信号;
		*/
		if (SYS_Role == Slave_Role)
		{
			tmp_char = SLAVE_RUN;
			Port_Send(fd, &tmp_char, 1, PORT_SENDandRECV_WAIT_MS, true);
			int PortRecvLength = Port_Recv(fd, &tmp_char, 1, PORT_SENDandRECV_WAIT_MS, true);
			Clear_Port_Register(fd, CLEAR_IN);/*清空串口接收缓存区*/
			if (PortRecvLength < 1)
			{
				count++;
				if (count < MAX_JUDGE_NUM)
					continue;
				for (i = 0; i < MAX_JUDGE_NUM; i++)
				{
					tmp_char = SLAVE_TRUE_MASTER;
					Port_Send(fd, &tmp_char, 1, PORT_SENDandRECV_WAIT_MS, true);
				}
				SYS_Role_Turn(Master_Alone_Role);
				count = 0;
				continue;
			}
			else
			{
				count = 0;
			}
		}
		/*
			主站接收从站消息：
			如果多次未接收到从站消息，则判定为从站离线；
			如果接收到从站消息，但是从站发送的消息为主站应该发送的消息，则表明此时两方身份都判定为了主站，则站号较大的切换为从站；
			如果接收到从站运行消息，且当前主站判定从站是不存在的，则切换状态为主站且从站存在；
			发送信息给从站
		*/
		else if (SYS_Role == Master_Alone_Role || SYS_Role == Master_Twins_Role)
		{
			tmp_char = MASTER_RUN;
			Port_Send(fd, &tmp_char, 1, PORT_SENDandRECV_WAIT_MS, true);
			int PortRecvLength = Port_Recv(fd, &tmp_char, 1, PORT_SENDandRECV_WAIT_MS, true);
			Clear_Port_Register(fd, CLEAR_IN);/*清空串口接收缓存区*/
			if (PortRecvLength < 1)
			{
				count++;
				if (count >= MAX_JUDGE_NUM)
				{
					count = MAX_JUDGE_NUM;
					if (SYS_Role == Master_Twins_Role)
						SYS_Role_Turn(Master_Alone_Role);
				}
			}
			else
			{
				count = 0;
				if ((tmp_char == MASTER_RUN || tmp_char == SLAVE_TRUE_MASTER) && (IPTail_Num > MASTER_SLAVE_ID_DT))
				{
					SYS_Role_Turn(Slave_Role);
					continue;
				}					
				else if (tmp_char == SLAVE_RUN)
				{
					if (SYS_Role == Master_Alone_Role)
						SYS_Role_Turn(Master_Twins_Role);
				}
			}
		}
	}

	

#undef MAX_JUDGE_NUM
#undef DELAY_MS
#undef PORT_SENDandRECV_WAIT_MS
}
